package il.adscan.scan.json.impl;

//import com.gargoylesoftware.htmlunit.html.HtmlPage;

import il.adscan.domain.Advertisement;
import il.adscan.domain.AdvertisementFilter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.LogFactory;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public abstract class BaseScanner implements AdScanner {

    static {
        LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog");
    }

    private Set<Advertisement> advertisementList = new HashSet<>();
    protected int pageCounter = 0; // Page from which parsing starting
    protected int lastPageToScan = -1; // End of parsing pages range
    protected int numberOfItemsToScan = -1;
    protected AdvertisementFilter filter;

    protected BaseScanner() {
    }

    @Override
    public Set<Advertisement> scan(AdvertisementFilter filter) throws IOException {
        this.filter = filter;
        Document htmlPage = getHtmlPageWithAppliedFilters(filter);
        numberOfItemsToScan = filter.getNumberOfItemsToScan();
        pageCounter = filter.getFirstPageToScan();
        lastPageToScan = filter.getLastPageToScan();
        scrapAllData(getPage(pageCounter, htmlPage.baseUri()));
        return advertisementList;
    }

    protected Document getHtmlPageWithAppliedFilters(AdvertisementFilter filter) throws IOException {
        Document htmlPage = getHTMLPage(getSiteURL());
        htmlPage = applyFilters(htmlPage, filter);
        return htmlPage;
    }

    private void scrapAllData(Document htmlPage) throws IOException {
        if (!isProcessCurrentPage(htmlPage)) {
            return;
        }
        advertisementList.addAll(scrapPageData(htmlPage));
        pageCounter++;
        if (hasNextPage(htmlPage) && advertisementList.size() < numberOfItemsToScan && (pageCounter <= lastPageToScan || lastPageToScan == -1)) {
            scrapAllData(getNextPage(htmlPage));
        }
    }

    protected abstract java.util.Set<Advertisement> scrapPageData(Document doc) throws IOException;

    protected Document getNextPage(Document htmlPage) throws IOException {
        return getPage(pageCounter, htmlPage.baseUri());
    }

    protected abstract Document getPage(int pageNumber, String baseURI) throws IOException;

    protected abstract boolean hasNextPage(Document htmlPage);

    protected abstract boolean isProcessCurrentPage(Document htmlPage);

    protected abstract Document applyFilters(Document htmlPage, AdvertisementFilter filter);

    protected Document getHTMLPage(String site) throws IOException {
        Document page = connect(site);
        return page;
    }

    protected Document connect(String site) throws IOException {
        return Jsoup.connect(site).timeout(20000).get();
    }

    protected String getParametersDelimiter(String baseURI) {
        return StringUtils.contains(baseURI, "?") ? "&" : "?";
    }

    public Set<Advertisement> getAdvertisementList() {
        return advertisementList;
    }
}
